﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.Threading;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using D3D = Microsoft.DirectX.Direct3D;
using MyDX;
using System.IO;
using ScreenSaver.Properties;

using Microsoft.DirectX.DirectSound;
using DS = Microsoft.DirectX.DirectSound;

using Microsoft.DirectX.AudioVideoPlayback;



namespace ScreenSaver
{
    struct PosQuat
    {
        public Vector3 Position;
        public Quaternion Rotation;
    }

    struct myownvertexformat
    {
        public Vector3 Pos;
        public Vector2 TexCoord;

        public myownvertexformat(Vector3 _Pos, float texx, float texy)
        {
            Pos = _Pos;
            TexCoord.X = texx;
            TexCoord.Y = texy;
        }
    }
        
    public partial class MainForm : Form
    {

        //---------------------------------------------------------------------------


        private IntPtr PreviewHandle;
        
        #region Preview API's

        [DllImport("user32.dll")]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

        #endregion

        bool IsPreviewMode = false;

        #region Constructors

        public MainForm()
        {
            InitializeComponent();
        }

        //This constructor is passed the bounds this form is to show in
        //It is used when in normal mode
        public MainForm(Rectangle Bounds)
        {
            InitializeComponent();

            this.InitializeKeyboard();
            this.InitializeDevice(); // Czwarta nowość. Trzeba zainicjować Device
            this.InitializeMeshes();
            this.InitializeTextures();

            //hide the cursor
            Cursor.Hide();
        }

        //This constructor is the handle to the select screensaver dialog preview window
        //It is used when in preview mode (/p)
        public MainForm(IntPtr PreviewHandle)
        {
            this.PreviewHandle = PreviewHandle;
            InitializeComponent();
        }

        #endregion

        #region GUI

        System.Timers.Timer t = new System.Timers.Timer();

        private void MainForm_Shown(object sender, EventArgs e)
        {
            if (Settings.Default.SoundtrackOn)
            {
                if(File.Exists(Settings.Default.Soundtrack))
                {
                    backmusic = new Audio(Settings.Default.Soundtrack);
                    backmusic.Play();
                }
            }
            if (Settings.Default.SoundEffectsOn)
            {
                sound.Play(0, BufferPlayFlags.Looping);
                Random rand = new Random();
                int randSec = rand.Next(10, 20);

                //t.Tick += new EventHandler(t_Tick);
                t.Elapsed += new System.Timers.ElapsedEventHandler(t_Tick);
                t.Interval = randSec * 1000;

                t.Start();
                t.Enabled = true;
            }
        }

    
        #endregion

        #region ScreenSaver User Input

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (!IsPreviewMode) //disable exit functions for preview
            {
                Application.Exit();
            }
        }

        private void MainForm_Click(object sender, EventArgs e)
        {
            if (!IsPreviewMode) //disable exit functions for preview
            {
                Application.Exit();
            }
        }

        //start off OriginalLoction with an X and Y of int.MaxValue, because
        //it is impossible for the cursor to be at that position. That way, we
        //know if this variable has been set yet.
        Point OriginalLocation = new Point(int.MaxValue, int.MaxValue);



        // Screen saver is of, if the mouse movement is more radical than just a accidental move
        private void MainForm_MouseMove(object sender, MouseEventArgs e)
        {
            if ((!IsPreviewMode) && (Settings.Default.MouseEnd)) //disable exit functions for preview
            {
                //see if originallocat5ion has been set
                if (OriginalLocation.X == int.MaxValue & OriginalLocation.Y == int.MaxValue)
                {
                    OriginalLocation = e.Location;
                }
                //see if the mouse has moved more than 20 pixels in any direction. If it has, close the application.
                if (Math.Abs(e.X - OriginalLocation.X) > 20 | Math.Abs(e.Y - OriginalLocation.Y) > 20)
                {
                    Application.Exit();
                }
            }

           
        }

        #endregion


        #region DX

      

        private MyObject terrain, ship, sky, water;
        private MyObject  light, tree;

        private Texture Dirt, Grass, Rock, Snow;

        private Texture Reflection, Refraction, WaterBumpMap, RockBumpMap;

        private RenderToSurface Rts;

        private Matrix mProjection, mView, mDepthProjection;

        private RenderToSurface Rts1, Rts2;
        private RenderToSurface Mrt1, Mrt2;
        private Texture MT1, MT2, MT3, MT4;
        private Surface SMT1, SMT2, SMT3, SMT4;

        private VertexBuffer mvb, mvbS;
        private VertexDeclaration mvd;

        private int MapSize = 512;
        private Texture Shadows, Sh1, Sh2, Sun;


        private CubeTexture Kostka;
        private Matrix mProjectionCube, mViewCube;
        Surface RenderSurface;
        private Vector2[] vSampleOffsets;
        private float vViewportTexelSizeH;
        private float vViewportTexelSizeW;
        private bool shoot;
        private float[] fSampleWeights;
        private int ShSrcState;

        private float WaterLevel = 14.0f;

        private Vector4 LightPosition;

        private float Time = 0;

        Vector3 cameraPosition = new Vector3(130, 30, -50);
        float leftrightRot = (float)(Math.PI / 2.0f);
        float updownRot = (float)(-Math.PI / 10.0f);
        const float rotationSpeed = 0.3f;
        const float moveSpeed = 30.0f;
        const float waterHeight = 5.0f;

        private float RotSpeed = 0.05f, FlightSpeed = 0.08f;

        private float mxTime = 0.0f;


        private const int CameraDelay = 55;
        private PosQuat[] ShipPositions;
        private int CamIndex = 0;
        private float fps;
        private int frames = 0, PrevTickCount = 1;


        //private const string xpath = @"c:\x\";
         private const string xpath = @"..\..\..\x\";
        private D3D.Device device;  //tu pierwsza nowość. Zmienna typu Device.

        private MyObject O;
        private System.ComponentModel.Container components = null;
        private Microsoft.DirectX.DirectInput.Device keyboard;

        private MyCamera Camera, Light;

        float time = 0.0f, time2 = 0.0f;

        float GlobalTime = 0.0f;
        private D3D.Font Font3D;

        private D3D.Effect effect;
        private D3D.Effect teffect;

        private Texture tex, tex2;

        private bool hardware;

        private Audio backmusic;


        public void InitializeKeyboard()
        {
            keyboard = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
            keyboard.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            keyboard.Acquire();
        }

        private void UpdateFramerate()
        {
            frames++;
            if (Math.Abs(Environment.TickCount - PrevTickCount) > 1000)
            {
                fps = (float)frames * 1000 / Math.Abs(Environment.TickCount - PrevTickCount);
                PrevTickCount = Environment.TickCount;
                frames = 0;
            }

        }

        public void InitializeMeshes()
        {
            //O = new MyObject(ref device);

            //O.LoadFromFile(xpath+"kulka2.x");
            //O.Normalize(Matrix.RotationX((float)Math.PI / 2));
            //O.NormalizeVB();

            //O.Position.X = 0.0f;
            //O.Position.Y = 1.0f;
            //O.Position.Z = 18.0f;

            terrain = new MyObject(ref device);
            ship = new MyObject(ref device);
            sky = new MyObject(ref device);
            water = new MyObject(ref device);
            if (File.Exists(xpath + "terrain.bmp"))
            {
                terrain.CreateTerrainFromFile(10, 3f, 3f, 0.2f, xpath + "terrain.bmp");
            }

            terrain.LoadTexture(0, xpath + "mars.bmp");
            terrain.Position = new Vector3(0, 0, 0);
            terrain.Rotation = Quaternion.Identity;
            terrain.NormalizeVB();
            terrain.CalculateBounds();


            sky.LoadFromFile(xpath + "sky.x");
            sky.Normalize(Matrix.RotationX((float)Math.PI / 2) * Matrix.Scaling(terrain.radius, terrain.radius, terrain.radius));
            sky.Rotation = Quaternion.Identity;
            sky.NormalizeVB();

            //ship.LoadFromFile("c:\\x\\tbomb.x");
            //ship.Normalize(Matrix.RotationX((float)Math.PI / 2));
            ship.Position = new Vector3(0, 0, 17);
            ship.Rotation = Quaternion.Identity;
            ship.radius = 10.0f;
            //ship.NormalizeVB();
            //ship.CalculateBounds();

            ShipPositions = new PosQuat[CameraDelay];
            for (int i = 0; i < CameraDelay; i++)
            {
                ShipPositions[i].Position = ship.Position;
                ShipPositions[i].Rotation = ship.Rotation;
            }




            water.CreateTerrainFromFile(1, 3f, 3f, 0.2f, xpath + "water.bmp");
            water.NormalizeVB();
            water.Position = new Vector3(0, 0, WaterLevel);
            water.Rotation = Quaternion.Identity;

            Dirt = TextureLoader.FromFile(device, xpath + "dirt.jpg");
            Grass = TextureLoader.FromFile(device, xpath + "grass.jpg");
            Rock = TextureLoader.FromFile(device, xpath + "rock.jpg");
            Snow = TextureLoader.FromFile(device, xpath + "snow.jpg");

            Camera = new MyCamera();

            Refraction = new Texture(device, MapSize, MapSize, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
            Reflection = new Texture(device, MapSize, MapSize, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);

            WaterBumpMap = TextureLoader.FromFile(device, xpath + "waterbump.jpg");
            RockBumpMap = TextureLoader.FromFile(device, xpath + "rockbump.jpg");

            light = new MyObject(ref device);
            light.LoadFromFile(xpath + "light.x");
            light.Normalize(Matrix.Scaling(0.1f, 0.1f, 0.1f));

            Light = new MyCamera();
            Light.Position = new Vector3(-0.5f, 0, 0f);

            tree = new MyObject(ref device);
            tree.LoadFromFile(xpath + "treea.x");
            tree.Normalize(Matrix.Identity * Matrix.Scaling(8f, 8f, 8f));
            //           tree.Position = new Vector3(0, 2, 19);
            tree.Rotation = Quaternion.Identity;
            tree.NormalizeVB();

            tree.Position = new Vector3(5,30,22);
            
            
            tree.RotateX(90.0f);

            Sun = TextureLoader.FromFile(device, xpath + "kolo.bmp");

            Camera = new MyCamera();
            //Camera.Position = new Vector3(0f, 0f, -tree.radius * 0.5f);
            //Camera.Up = new Vector3(0, 1.0f, 0);

            Kostka = new CubeTexture(device, MapSize, 1, Usage.RenderTarget, Format.R32F, Pool.Default);



            Shadows = new Texture(device, 1024, 1024, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
            Sh1 = new Texture(device, 1024, 1024, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
            Sh2 = new Texture(device, 1024, 1024, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
            vSampleOffsets = new Vector2[16];
            fSampleWeights = new float[16];
            shoot = true;
            ShSrcState = 0;

            ship.Position = tree.Position - new Vector3(-5, 0, 0);
            Camera.Position = tree.Position - new Vector3(0,-20,2);

            Camera.Up = new Vector3(0, 0, 1.0f);
           
        }

        public void InitializeTextures()
        {
            if (File.Exists(xpath + @"rock.jpg"))
                tex = TextureLoader.FromFile(device, xpath + @"rock.jpg");
            if (File.Exists(xpath + @"snow.jpg"))
                tex2 = TextureLoader.FromFile(device, xpath + @"snow.jpg");
        }

        private void RenderObject(MyObject O, Matrix V, Matrix P)
        {

            effect.SetValue("xRotationMatrix", Matrix.RotationQuaternion(O.Rotation));
            device.SetStreamSource(0, O.vb, 0);
            device.VertexDeclaration = O.vd;
            effect.SetValue("xWorld", Matrix.RotationQuaternion(O.Rotation) * Matrix.Translation(O.Position));
            effect.SetValue("xView", V);
            effect.SetValue("xProjection", P);


            int passes = effect.Begin(0);
            for (int i = 0; i < passes; i++)
            {
                effect.BeginPass(i);

                O.Render(ref effect, "xTexture");

                effect.EndPass();
            }
            effect.End();
        }

        private void RenderScene()
        {


            effect.SetValue("xRefraction", false);
            effect.SetValue("xReflection", false);
            effect.CommitChanges();
            effect.Technique = "multitextured";
            RenderObject(terrain, mView, mProjection);

            effect.Technique = "water";
            RenderObject(water, mView, mProjection);

            effect.Technique = "nolighttextured";
            RenderObject(sky, mView, mProjection);

            //effect.Technique = "textured";
            //RenderObject(ship, mView, mProjection);

        }

        //public void UpdateCamera()
        //{
        //    Camera.Position = new Vector3(O.radius * 5.0f * (float)Math.Sin(time), -O.radius * 5.0f * (float)Math.Cos(time), O.radius * 5.0f * (float)Math.Sin(time2));
        //    Camera.Up = new Vector3(0, 0, 1.0f);
        //    float aspect_ratio = this.Width / (float)this.Height;
        //    mProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, aspect_ratio, 0.02f, O.radius * 10);  // macierz projekcji
        //    mView = Camera.ViewMatrix(O.center);
        //}

        public void UpdateCamera()
        {

            //Camera.Position = new Vector3(0, -ship.radius * 5.0f, 0.5f);
            //Camera.Up = new Vector3(0, 0, 1.0f);

            //Vector3 CP = new Vector3(0, 0, 0);
            //Quaternion CR = Quaternion.Zero;

            //for (int i = 0; i < CameraDelay; i++)
            //{
            //    CP += ShipPositions[i].Position;
            //    CR += ShipPositions[i].Rotation;
            //}
            //CP.Multiply(1 / (float)CameraDelay);
            //CR.X /= (float)CameraDelay;
            //CR.Y /= (float)CameraDelay;
            //CR.Z /= (float)CameraDelay;
            //CR.W /= (float)CameraDelay;



            //Camera.TransformPosition(Matrix.RotationQuaternion(CR));
            //Camera.TransformPosition(Matrix.Translation(CP));
            //Camera.TransformUp(Matrix.RotationQuaternion(CR));

            float aspect_ratio = this.Width / (float)this.Height;
            mProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, aspect_ratio, 0.02f, 256 * 120);  // macierz projekcji
            mView = Camera.ViewMatrix(ship.Position);


            //ShipPositions[CamIndex].Position = ship.Position;
            //ShipPositions[CamIndex].Rotation = ship.Rotation;
            //CamIndex++;
            //if (CamIndex >= CameraDelay) CamIndex = 0;


           // float aspect_ratio = this.Width / (float)this.Height;
            // mProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, aspect_ratio, 0.02f, sky.radius * 5);  // macierz projekcji
             //mView = Camera.ViewMatrix(tree.center);
        }

        public void UpdateLights()
        {
            LightPosition = new Vector4(0.0f, 50.0f, 50.0f, 0.0f);
        }

        public void InitializeDevice() // Druga nowość. Inicjujemy urządzenie.
        {
            PresentParameters presentParams = new PresentParameters();

            // FULL SCREEN
            presentParams.BackBufferWidth = 800;
            presentParams.BackBufferHeight = 600;
            presentParams.BackBufferFormat = Format.R5G6B5;
           // presentParams.Windowed = false;
            presentParams.Windowed = true;

           // presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;
            presentParams.AutoDepthStencilFormat = DepthFormat.D16;
            presentParams.EnableAutoDepthStencil = true;


            D3D.Caps DevCaps = D3D.Manager.GetDeviceCaps(0, D3D.DeviceType.Hardware);
            D3D.DeviceType DevType = D3D.DeviceType.Reference;
            CreateFlags DevFlags = CreateFlags.SoftwareVertexProcessing;
            
            // Check if hardware shader is available
            if ((DevCaps.VertexShaderVersion >= new Version(2, 0)) && (DevCaps.PixelShaderVersion >= new Version(2, 0)))
            {
                DevType = D3D.DeviceType.Hardware;
                if (DevCaps.DeviceCaps.SupportsHardwareTransformAndLight)
                {
                    DevFlags = CreateFlags.HardwareVertexProcessing;
                    if (DevCaps.DeviceCaps.SupportsPureDevice)
                    {
                        DevFlags |= CreateFlags.PureDevice;
                    }
                }

                hardware = true;
            }

            device = new D3D.Device(0, DevType, this, DevFlags, presentParams);
            
            //device = new D3D.Device(0, D3D.DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
            
            System.Drawing.Font Font2D = new System.Drawing.Font("Arial", 12f, FontStyle.Regular);
            Font3D = new D3D.Font(device, Font2D);

            if (File.Exists(xpath + @"effects\effect_e.fx"))
                effect = D3D.Effect.FromFile(device, xpath + @"effects\effect_e.fx", null, ShaderFlags.None, null);
            if (File.Exists(xpath + @"effects\effect.fx"))
                teffect = D3D.Effect.FromFile(device, xpath + @"effects\effect.fx", null, ShaderFlags.None, null);
             //   effect = D3D.Effect.FromFile(device, xpath + @"simple\5.fx", null, ShaderFlags.None, null);

            Rts = new RenderToSurface(device, MapSize, MapSize, Format.X8R8G8B8, true, DepthFormat.D16);


            Rts1 = new RenderToSurface(device, MapSize, MapSize, Format.R32F, true, DepthFormat.D16);

            Rts2 = new RenderToSurface(device, 1024, 1024, Format.X8R8G8B8, true, DepthFormat.D16);


            mvb = new VertexBuffer(typeof(myownvertexformat), 4, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Texture0, Pool.Managed);
            mvbS = new VertexBuffer(typeof(myownvertexformat), 4, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Texture0, Pool.Managed);

            myownvertexformat[] vertices = new myownvertexformat[4];
            myownvertexformat[] verticesW = new myownvertexformat[4];

            vertices[0] = new myownvertexformat(new Vector3(-1.0f, 1.0f, 0), 0.0f, 0.0f);
            vertices[1] = new myownvertexformat(new Vector3(1.0f, 1.0f, 0), 1.0f, 0.0f);
            vertices[2] = new myownvertexformat(new Vector3(-1.0f, -1.0f, 0), 0.0f, 1.0f);
            vertices[3] = new myownvertexformat(new Vector3(1.0f, -1.0f, 0), 1.0f, 1.0f);

            verticesW[0] = new myownvertexformat(new Vector3(-0.5f, 0.5f, 0), 0.0f, 0.0f);
            verticesW[1] = new myownvertexformat(new Vector3(0.5f, 0.5f, 0), 1.0f, 0.0f);
            verticesW[2] = new myownvertexformat(new Vector3(-0.5f, -0.5f, 0), 0.0f, 1.0f);
            verticesW[3] = new myownvertexformat(new Vector3(0.5f, -0.5f, 0), 1.0f, 1.0f);


            mvb.SetData(vertices, 0, LockFlags.None);
            mvbS.SetData(verticesW, 0, LockFlags.None);

            VertexElement[] velements = new VertexElement[]
             {
                 new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
                 new VertexElement(0, 12, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0),
                 VertexElement.VertexDeclarationEnd
             };
            mvd = new VertexDeclaration(device, velements);

            MT1 = new Texture(device, this.device.Viewport.Width, this.device.Viewport.Height, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
            MT2 = new Texture(device, this.device.Viewport.Width, this.device.Viewport.Height, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);

            SMT1 = MT1.GetSurfaceLevel(0);
            SMT2 = MT2.GetSurfaceLevel(0);
        }

        private double azymut = 0;
        private double elewacja = 0;

        private void ReadKeyboard()
        {
            

            KeyboardState keys = keyboard.GetCurrentKeyboardState();

            if (keys[Settings.Default.KeyEnd])
            {
                Application.Exit();
            }


            float RotY = 0, RotX = 0;
            bool pressed = false;
            Vector3 przes = new Vector3(ship.Position.X,ship.Position.Y,ship.Position.Z);
            przes = przes - Camera.Position;
            double R = przes.Length();
            przes.Normalize();
            if (keys[Key.A])
            {
                //FlightSpeed *= 1.05f;
                Camera.Position = Camera.Position + przes;
                ship.Position = ship.Position + przes;
                
            }
            if (keys[Key.Z])
            {
                //FlightSpeed *= 0.95f;
                Camera.Position = Camera.Position - przes;
                ship.Position = ship.Position - przes;
                
            }
            if (keys[Key.Down])
            {
                elewacja += 0.1;
                //if (elewacja >= Math.PI * 2)
                //{ elewacja = 0; }
                pressed = true;
            }
            if (keys[Key.Up])
            {
                elewacja -= 0.1;
                //if (elewacja <= 0)
                //{ elewacja = Math.PI * 2; }
                pressed = true;
            }
            if (keys[Key.Left])
            {
                azymut += 0.1;
                //if (azymut >=  Math.PI * 2)
                //{ azymut = 0;}
                pressed = true;
            }
            if (keys[Key.Right])
            {
                azymut -= 0.1;
                //if (azymut <= 0)
                //{ azymut = Math.PI * 2; }
                pressed = true;
            }



            if (pressed)
            {
                ship.Position.X = Camera.Position.X + (float)(R * Math.Cos(azymut) * Math.Cos(elewacja));
                ship.Position.Y = Camera.Position.Y + (float)(R * Math.Sin(elewacja));
                ship.Position.Z = Camera.Position.Z + (float)(R * Math.Sin(azymut) * Math.Cos(elewacja));
            }

            pressed = false;
            if (keys[Key.S])
            {
                WaterLevel += 0.1f;
                pressed = true;
            }
            if (keys[Key.X])
            {
                WaterLevel -= 0.1f;
                pressed = true;
            }

            // Light
            if (keys[Key.U])
            {
                Light.CP.X += 1;
            }
            if (keys[Key.J])
            {
                Light.CP.X -= 1;
            }
            if (keys[Key.I])
            {
                Light.CP.Y += 1;
            }
            if (keys[Key.K])
            {
                Light.CP.Y -= 1;
            }
            if (keys[Key.O])
            {
                Light.CP.Z += 1;
            }
            if (keys[Key.L])
            {
                Light.CP.Z -= 1;
            }
            if (keys[Key.P])
            {
                //sound.Play(0,BufferPlayFlags.Looping); 
                //backmusic = new Audio(Settings.Default.Soundtrack);
                //backmusic.Play();
                
            }


            water.Position = new Vector3(0, 0, WaterLevel);
            //ship.RotateY(RotY);
            //ship.RotateX(RotX);

            //Vector3 TempVec = new Vector3(0, 1, 0);
           // Vector4 V = Vector3.Transform(TempVec, Matrix.RotationQuaternion(ship.Rotation));
            //V.Normalize();


            //ship.Position += (new Vector3(V.X,V.Y,V.Z)) * FlightSpeed ;
            
            if (!pressed)
            {
                //Vector3 Axis = new Vector3();
                //float Angle = 0;
                //Quaternion.ToAxisAngle(ship.Rotation, ref  Axis, ref Angle);
                
                
                //Axis.Y=Axis.X = 0;
                ////Axis.Normalize();
                //Quaternion TempRot = Quaternion.RotationAxis(Axis, Angle);

                //ship.Rotation = Quaternion.Slerp(TempRot, ship.Rotation, 0.95f);

             
            }

            
        }




        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) //Trzecia nowość. W zdarzeniu OnPaint będziemy rysować. 
        {

            ReadKeyboard();
            UpdateLights();
            UpdateCamera();
            UpdateFramerate();



            effect.SetValue("xDirtTexture", Dirt);
            effect.SetValue("xGrassTexture", Grass);
            effect.SetValue("xRockTexture", Rock);
            effect.SetValue("xSnowTexture", Snow);
            effect.SetValue("xMinHeight", 0);
            effect.SetValue("xMaxHeight", 40);
            effect.SetValue("xLightPosition", LightPosition);
            effect.SetValue("xAmbientLight", new Vector4(0.05f, 0.05f, 0.1f, 0.0f));
            effect.SetValue("xRockBumpMap", RockBumpMap);
            effect.SetValue("xRockBumpHeight", 0.3f);

            effect.SetValue("xWaterLevel", WaterLevel);
            effect.SetValue("xReflectedView", ReflectCamera());
            effect.SetValue("xCameraPosition", new Vector4(Camera.Position.X, Camera.Position.Y, Camera.Position.Z, 1.0f));
            effect.SetValue("xWaterBumpMap", WaterBumpMap);
            effect.SetValue("xWaveLength", 0.03f);
            effect.SetValue("xWaveHeight", 0.5f);
            effect.SetValue("xWaterColor", new Vector4(0.0f, 0.1f, 0.2f, 0.0f));
            effect.SetValue("xTime", Time);
            effect.SetValue("xWindSpeed", 0.01f);


            Time += 0.1f;

            RenderReflection();
            //RenderRefraction();
           // effect.SetValue("xRefractionMap", Refraction);
            effect.SetValue("xReflectionMap", Reflection);




            device.BeginScene(); // początek sceny 
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Yellow, 1.0f, 0);

            RenderScene();


            Font3D.DrawText(null, string.Format("{0:0.00} FPS", fps), new Point(10, 10), Color.White);
            Font3D.DrawText(null, string.Format("view: {0},{0},{0}", ship.Position.X,ship.Position.Y,ship.Position.Z), new Point(10, 30), Color.White);
            Font3D.DrawText(null, string.Format("camera: {0},{0},{0}", Camera.Position.X - tree.Position.X, Camera.Position.Y - tree.Position.Y, Camera.Position.Z - tree.Position.Z), new Point(10, 60), Color.White);


            #region Drzewo

            int numpasses;
            int passes;

            device.SetRenderTarget(1, SMT2);

            //device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);

            //teffect.Technique = "sky";

            //teffect.SetValue("xRotationMatrix", Matrix.Identity);
            //passes = effect.Begin(0);
            //for (int i = 0; i < passes; i++)
            //{
            //    teffect.BeginPass(i);
            //    device.SetStreamSource(0, room.vb, 0);
            //    device.VertexDeclaration = room.vd;
            //    teffect.SetValue("xWorld", Matrix.Identity);
            //    teffect.SetValue("xView", mView);
            //    teffect.SetValue("xProjection", mProjection);
            //    teffect.CommitChanges();
            //    room.Render(ref effect, "xTexture");
            //    teffect.EndPass();
            //}
            //teffect.End();


            // The SUN ------
            device.RenderState.ZBufferWriteEnable = false;
            device.SetStreamSource(0, mvbS, 0);
            device.VertexDeclaration = mvd;
            teffect.Technique = "sun";
            teffect.SetValue("xSunBrush", Sun);


            teffect.SetValue("g_vSunPosition", new Vector4(Light.Position.X, Light.Position.Y , Light.Position.Z , 0.0f));//new Vector4(0,0,0,1));
            teffect.CommitChanges();
            numpasses = teffect.Begin(0);
            for (int i = 0; i < numpasses; i++)
            {
                teffect.BeginPass(i);
                device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
                teffect.EndPass();
            }
            teffect.End();
            device.RenderState.ZBufferWriteEnable = true;

            // Tree
            mxTime += 0.05f;
            teffect.Technique = "texturedalpha";
            teffect.SetValue("xRotationMatrix", Matrix.RotationQuaternion(tree.Rotation));
            teffect.SetValue("xMagnitude", 0.0005f);
            teffect.SetValue("xTime2", mxTime);
            teffect.SetValue("xLightPosition", new Vector4(Light.Position.X, Light.Position.Y , Light.Position.Z , 1.0f));

            passes = teffect.Begin(0);
            for (int i = 0; i < passes; i++)
            {
                teffect.BeginPass(i);

                device.SetStreamSource(0, tree.vb, 0);
                device.VertexDeclaration = tree.vd;
                teffect.SetValue("xWorld", Matrix.RotationQuaternion(tree.Rotation) * Matrix.Translation(tree.Position));
                teffect.SetValue("xView", mView);
                teffect.SetValue("xProjection", mProjection);
                teffect.CommitChanges();
                tree.Render(ref teffect, "xTexture");

                teffect.EndPass();
            }
            teffect.End();
            device.SetRenderTarget(1, null);

            device.RenderState.ZBufferWriteEnable = false;
            device.RenderState.ZBufferEnable = false;

            device.SetStreamSource(0, mvb, 0);
            device.VertexDeclaration = mvd;
            teffect.Technique = "shaft";
            teffect.SetValue("xSunBrush", MT2);
            teffect.SetValue("xDeffered1", MT1);

            //teffect.SetValue("Decay", 0.93f);
            //teffect.SetValue("Exposure", 0.7f);
            //teffect.SetValue("Weight", 0.3f);
            //teffect.SetValue("Density", 2.0f);
            teffect.SetValue("Decay", 0.98f);
            teffect.SetValue("Exposure", 0.1f);
            teffect.SetValue("Weight", 0.1f);
            teffect.SetValue("Density", 1.0f);
            teffect.SetValue("ScreenLightPos", new Vector4(Light.Position.X / 2.0f + 0.5f, -Light.Position.Y / 2.0f + 0.5f, Light.Position.Z, 1.0f));//new Vector4(0.0f, 0.0f, 0.0f, 1.0f));

            teffect.CommitChanges();
            numpasses = teffect.Begin(0);
            for (int i = 0; i < numpasses; i++)
            {
                teffect.BeginPass(i);
                device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
                teffect.EndPass();
            }
            teffect.End();

            device.RenderState.ZBufferWriteEnable = true;
            device.RenderState.ZBufferEnable = true;


            #endregion

            device.EndScene();  //koniec sceny

            device.Present(); //tu informujemy, że Device już jest gotowe.
            this.Invalidate(); //to po to aby windows przerysował formę


        }

        private void RenderRefraction()
        {

            effect.SetValue("xRefraction", true);
            effect.SetValue("xReflection", false);

            Surface RenderSurface = Refraction.GetSurfaceLevel(0);

            Rts.BeginScene(RenderSurface);

            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
            effect.Technique = "multitextured";
            RenderObject(terrain, mView, mProjection);
            Rts.EndScene(Filter.None);

        }

        private void RenderReflection()
        {
            Matrix mReflView = ReflectCamera();

            effect.SetValue("xRefraction", false);
            effect.SetValue("xReflection", true);
            Surface RenderSurface = Reflection.GetSurfaceLevel(0);

            Rts.BeginScene(RenderSurface);

            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
            effect.Technique = "multitextured";
            RenderObject(terrain, mReflView, mProjection);

            effect.Technique = "nolighttextured";

            RenderObject(sky, mReflView, mProjection);


            // effect.Technique = "textured";
            // RenderObject(ship, mReflView, mProjection);

            Rts.EndScene(Filter.None);
        }


        public Matrix ReflectCamera()
        {
            Vector3 RCamPos, RCamUp, RTarget;
            RCamPos = Camera.Position;
            RCamPos.Z = -RCamPos.Z + 2 * WaterLevel;
            RTarget = ship.Position;
            RTarget.Z = -RTarget.Z + 2 * WaterLevel;
            Vector3 Side = Vector3.Cross(Camera.Up, (ship.Position - Camera.Position));
            Side.Z = -Side.Z;
            RCamUp = -Vector3.Cross(Side, RTarget - RCamPos);
            Matrix RView = Matrix.LookAtLH(RCamPos, RTarget, RCamUp);
            return RView;
        }

        protected override void Dispose(bool disposing) // tu zwalniamy wszystkie komponenty
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }
        private void InitializeComponent() // tu metoda inicjująca komponenty
        {

            

            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true); //tu drugi dodatek, aby Windows dobrze przerysowywał okno.

            this.MouseMove +=new MouseEventHandler(MainForm_MouseMove);

            this.ClientSize = new System.Drawing.Size(800, 600);
            this.Name = "WinForm";
            this.Text = "Screen Saver";

            if (Settings.Default.SoundEffectsOn)
            {
                ExecuteSound();
            }
            this.Shown +=new EventHandler(MainForm_Shown);
           

        }

        private void StartSound()
        {
            Thread snd = new Thread(ExecuteSound);
            snd.Start();
        }

        private bool playing;
        private DS.Device dSound;
        private BufferDescription bufferDescription;
        private SecondaryBuffer sound;
        private SecondaryBuffer sound2;
        private DS.EffectDescription[] fx = new DS.EffectDescription[1]; 
        //private SecondaryBuffer sound3;

        private void ExecuteSound()
        {
            DevicesCollection devList = new DevicesCollection();

            dSound = new DS.Device(devList[0].DriverGuid);

           
            dSound.SetCooperativeLevel(this.Handle, CooperativeLevel.Priority);
            
            
            bufferDescription = new BufferDescription();
            bufferDescription.Flags = BufferDescriptionFlags.ControlVolume | BufferDescriptionFlags.ControlFrequency | BufferDescriptionFlags.ControlPan | BufferDescriptionFlags.ControlEffects;
		

            try
            {
                playing = false;
                if (sound != null)
                {
                    sound.Stop();
                }
            }
            catch { }
            if (File.Exists(xpath + "river.wav"))
            {
                sound = new SecondaryBuffer(xpath+"river.wav", bufferDescription, dSound);
                sound.Volume = -50;
            }
            if (File.Exists(xpath + "Morning.wav"))
            {
                sound2 = new SecondaryBuffer(xpath + "Morning.wav", bufferDescription, dSound);
                fx[0] = new DS.EffectDescription();
                fx[0].GuidEffectClass = DSoundHelper.StandardEchoGuid;
                sound2.SetEffects(fx);
            }
           
            
        }

        private void t_Tick(object sender, EventArgs e)
        {
            if (playing)
            {
                sound2.Stop();
                playing = false;
            }
            else
            {
                sound2.Play(0, BufferPlayFlags.Default);
                playing = true;
            }

            t.Stop();
            Random rand = new Random();
            int randSec = rand.Next(10, 20);
            t.Interval = randSec * 500;
            t.Start();
            t.Enabled = true;


        }

        #endregion
    }
}
